package com.meelive.ingkee.iknetwork.diagnose.impl

import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.text.TextUtils
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentFactory
import com.meelive.ingkee.base.utils.text.StringUtils
import com.meelive.ingkee.iknetwork.diagnose.CheckNetworkActivity
import com.meelive.ingkee.iknetwork.diagnose.DefaultCheckNetworkFragment
import com.meelive.ingkee.iknetwork.diagnose.api.DiagnoseApiException
import com.meelive.ingkee.iknetwork.diagnose.api.IKNetworkDiagnoseContract
import com.meelive.ingkee.iknetwork.diagnose.model.CopyViewConfig
import com.meelive.ingkee.iknetwork.diagnose.model.IKNetworkDiagnoseBaseInfo
import com.meelive.ingkee.iknetwork.diagnose.model.TitleViewConfig
import com.meelive.ingkee.iknetwork.diagnose.repo.AppConfigServiceRepo
import com.meelive.ingkee.iknetwork.diagnose.util.DiagnosePares
import io.reactivex.Observable
import okhttp3.OkHttpClient

@SuppressLint("CheckResult")
class IKNetworkDiagnoseService private constructor(val intent: Intent) {

    companion object {
        private const val EXTRA_HOST = "extra_host"
        private const val EXTRA_URL = "extra_url"
        private const val EXTRA_URL_KEY = "extra_url_key"
    }

    @JvmOverloads fun startNetworkDiagnose(okHttpClient: OkHttpClient? = null, context: Context, callback: (errorMsg: String) -> Unit) {

        val host = if (intent.hasExtra(EXTRA_HOST)) intent.getStringExtra(EXTRA_HOST) else null
        val url = if (intent.hasExtra(EXTRA_URL)) intent.getStringExtra(EXTRA_URL) else null
        val key = if (intent.hasExtra(EXTRA_URL_KEY)) intent.getStringExtra(EXTRA_URL_KEY) else null

        val baseInfoStr = if (intent.hasExtra(CheckNetworkActivity.BASE_INFO_JSON)) intent.getStringExtra(CheckNetworkActivity.BASE_INFO_JSON) else null
        val fragmentName: String? = if (intent.hasExtra(CheckNetworkActivity.CONTENT_FRAGMENT_NAME)) intent.getStringExtra(CheckNetworkActivity.CONTENT_FRAGMENT_NAME) else ""

        Observable.just("")
                .flatMap {
                    checkBaseInfo(baseInfoStr)
                    checkUrl(host, url, key)
                    checkFragment(fragmentName)
                    AppConfigServiceRepo.reqAppConfig(okHttpClient, host!!, url!!, key!!)
                }
                .subscribe({
                    intent.setClass(context, CheckNetworkActivity::class.java)
                    intent.putExtra(CheckNetworkActivity.CONFIG_JSON, DiagnosePares.toJson(it))
                    startActivity(context, intent)
                }, {
                    callback.invoke(it.message ?: "未知错误")
                })
    }

    private fun checkBaseInfo(baseInfoStr: String?) {
        takeIf { StringUtils.isEmpty(baseInfoStr) }?.apply {
            throw DiagnoseApiException(DiagnoseApiException.ERR_UNKNOWN, "network diagnose base info is null")
        }
    }

    private fun checkUrl(host: String?, url: String?, key: String?) {
        when {
            TextUtils.isEmpty(host) -> {
                throw DiagnoseApiException(DiagnoseApiException.ERR_UNKNOWN, "AppConfig host is null")
            }

            TextUtils.isEmpty(url) -> {
                throw DiagnoseApiException(DiagnoseApiException.ERR_UNKNOWN, "AppConfig url is null")
            }

            TextUtils.isEmpty(key) -> {
                throw DiagnoseApiException(DiagnoseApiException.ERR_UNKNOWN, "AppConfig http request param is null")
            }
        }
    }

    private fun checkFragment(fragmentName: String?) {
        javaClass.classLoader?.let {
            val instantiate = FragmentFactory().instantiate(it, fragmentName!!)
            if (instantiate !is IKNetworkDiagnoseContract) {
                throw DiagnoseApiException(DiagnoseApiException.ERR_UNKNOWN, "fragment does not implements IKNetworkDiagnoseContract")
            }
        } ?: kotlin.run {
            throw DiagnoseApiException(DiagnoseApiException.ERR_UNKNOWN, "ClassLoader is null, can not load fragment: $fragmentName")
        }
    }

    class Builder {

        private var fragmentName: String? = DefaultCheckNetworkFragment::class.java.canonicalName
        private var path: String? = null
        private var urlKey: String? = null
        private var host: String? = null
        private var copyViewConfig: String? = null
        private var titleViewConfig: String? = null
        private var baseInfo: String? = null

        fun <T : Fragment> setContentFragment(fragment: Class<T>): Builder {
            this.fragmentName = fragment.canonicalName
            return this
        }

        fun setBaseInfo(info: IKNetworkDiagnoseBaseInfo): Builder {
            baseInfo = DiagnosePares.toJson(info)
            return this
        }

        fun setAppConfigUrl(host: String, path: String): Builder {
            this.host = host
            this.path = path
            return this
        }

        fun setAppConfigParam(key: String): Builder {
            this.urlKey = key
            return this
        }

        fun setCopyCheckViewConfig(config: CopyViewConfig): Builder {
            copyViewConfig = DiagnosePares.toJson(config)
            return this
        }

        fun setTitleViewConfig(config: TitleViewConfig): Builder {
            titleViewConfig = DiagnosePares.toJson(config)
            return this
        }

        fun build(): IKNetworkDiagnoseService {
            return IKNetworkDiagnoseService(Intent().apply {
                putExtra(EXTRA_HOST, host)
                putExtra(EXTRA_URL, "${host}${path}")
                putExtra(EXTRA_URL_KEY, urlKey)
                putExtra(CheckNetworkActivity.BASE_INFO_JSON, baseInfo)
                putExtra(CheckNetworkActivity.COPY_VIEW_CONFIG, copyViewConfig)
                putExtra(CheckNetworkActivity.TITLE_VIEW_CONFIG, titleViewConfig)
                putExtra(CheckNetworkActivity.CONTENT_FRAGMENT_NAME, fragmentName)
            })
        }
    }

    private fun startActivity(context: Context, intent: Intent) {
        if (context !is Activity) {
            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        }
        context.startActivity(intent)
    }
}
